﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace Notepad_Clone
{
    partial class NotepadClone : Window
    {
        // 应用名称--标题栏显示名称
        protected string strAppTitle;

        // 配置文件保存路径
        protected string strAppData;

        protected NotepadCloneSettings settings;

        /// <summary>
        /// 是否有变动
        /// </summary>
        protected bool isFileDirty = false;

        protected Menu menu;
        protected TextBox txtbox;
        protected StatusBar status;

        string strLoadedFile;
        StatusBarItem statLineCol;

        public NotepadClone()
        {
            Assembly asmbly = Assembly.GetExecutingAssembly();
            AssemblyTitleAttribute title = (AssemblyTitleAttribute)asmbly.
                                                GetCustomAttributes(typeof(AssemblyTitleAttribute), false)[0];
            this.strAppTitle = title.Title;

            AssemblyProductAttribute product = (AssemblyProductAttribute)asmbly.
                                                GetCustomAttributes(typeof(AssemblyProductAttribute), false)[0];
            this.strAppData = Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                "pisDad\\" + product.Product + "\\" + product.Product + ".Settings.xml");

            DockPanel dock = new DockPanel();
            this.Content = dock;

            this.menu = new Menu();
            dock.Children.Add(this.menu);
            DockPanel.SetDock(this.menu, Dock.Top);

            this.status = new StatusBar();
            dock.Children.Add(this.status);
            DockPanel.SetDock(this.status, Dock.Bottom);

            this.statLineCol = new StatusBarItem();
            this.statLineCol.HorizontalAlignment = HorizontalAlignment.Right;
            this.status.Items.Add(this.statLineCol);
            DockPanel.SetDock(this.statLineCol, Dock.Right);

            this.txtbox = new TextBox()
            {
                AcceptsReturn = true,
                AcceptsTab = true,
                VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
                HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
            };
            this.txtbox.TextChanged += this.TextBoxOnTextChanged;
            this.txtbox.SelectionChanged += this.TextBoxOnSelectionChanged;
            dock.Children.Add(this.txtbox);

            this.AddFileMenu(this.menu);
            this.AddEditMenu(this.menu);
            this.AddFormatMenu(this.menu);
            this.AddViewMenu(this.menu);
            this.AddHelpMenu(this.menu);

            this.settings = (NotepadCloneSettings)this.LoadSettings();

            this.WindowState = settings.WindowState;
            if (settings.RestoreBounds != Rect.Empty)
            {
                this.Left = settings.RestoreBounds.Left;
                this.Top = settings.RestoreBounds.Top;
                this.Width = settings.RestoreBounds.Width;
                this.Height = settings.RestoreBounds.Height;
            }

            this.txtbox.TextWrapping = settings.TextWrapping;
            this.txtbox.FontFamily = new System.Windows.Media.FontFamily(settings.FontFamily);
            this.txtbox.FontStyle = (FontStyle)new FontStyleConverter().ConvertFromString(settings.FontStyle);
            this.txtbox.FontWeight = (FontWeight)new FontWeightConverter().ConvertFrom(settings.FontWeight);
            this.txtbox.FontStretch = (FontStretch)new FontStretchConverter().ConvertFromString(settings.FontStretch);
            this.txtbox.FontSize = settings.FontSize;

            this.Loaded += WindowOnLoad;

            this.txtbox.Focus();
        }

        #region override method
        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            e.Cancel = !this.OkToTrash();
            this.settings.RestoreBounds = this.RestoreBounds;
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            this.settings.WindowState = this.WindowState;
            this.settings.TextWrapping = this.txtbox.TextWrapping;
            this.settings.FontFamily = this.txtbox.FontFamily.ToString();
            this.settings.FontStyle = new FontStyleConverter().ConvertToString(this.txtbox.FontStyle);
            this.settings.FontWeight = new FontWeightConverter().ConvertToString(this.txtbox.FontWeight);
            this.settings.FontStretch = new FontStretchConverter().ConvertToString(this.txtbox.FontStretch);
            this.settings.FontSize = this.txtbox.FontSize;
            this.SaveSettings();
        }
        #endregion

        #region private method
        private void UpdateTitle()
        {
            if (this.strLoadedFile == null)
            {
                this.Title = "Untitled - " + this.strAppTitle;
            }
            else
            {
                this.Title = Path.GetFileName(this.strLoadedFile) + " - " + this.strAppTitle;
            }
        }
        #endregion

        #region virtual method
        protected virtual object LoadSettings()
        {
            return NotepadCloneSettings.Load(typeof(NotepadCloneSettings), this.strAppData);
        }

        protected virtual void SaveSettings()
        {
            this.settings.Save(this.strAppData);
        }
        #endregion

        #region event handler
        private void WindowOnLoad(object sender, RoutedEventArgs e)
        {
            ApplicationCommands.New.Execute(null, this);

            string[] strArgs = Environment.GetCommandLineArgs();
            if (strArgs.Length > 1)
            {
                if (File.Exists(strArgs[1]))
                {
                    this.LoadFile(strArgs[1]);
                }
                else
                {
                    MessageBoxResult result = MessageBox.Show(
                        "Cannot find the " + Path.GetFileName(strArgs[1]) + " file.\r\n\r\n" +
                        "Do you want to create a new file?",
                        this.strAppTitle,
                        MessageBoxButton.YesNoCancel,
                        MessageBoxImage.Question);
                    if (result == MessageBoxResult.Cancel)
                    {
                        this.Close();
                    }
                    else if (result == MessageBoxResult.Yes)
                    {
                        try
                        {
                            File.Create(strLoadedFile = strArgs[1]).Close();
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(
                                "Error on File Creation: " + ex.Message,
                                this.strAppTitle,
                                MessageBoxButton.OK,
                                MessageBoxImage.Asterisk);
                            throw;
                        }

                        this.UpdateTitle();
                    }
                }
            }
        }

        private void TextBoxOnSelectionChanged(object sender, RoutedEventArgs e)
        {
            int iChar = this.txtbox.SelectionStart;
            int iLine = this.txtbox.GetLineIndexFromCharacterIndex(iChar);

            if (iLine == -1)
            {
                this.statLineCol.Content = string.Empty;
                return;
            }

            int iCol = iChar - this.txtbox.GetCharacterIndexFromLineIndex(iLine);
            string str = string.Format("Line {0} Col {1}", iLine + 1, iCol + 1);
            if (this.txtbox.SelectionLength > 0)
            {
                iChar += this.txtbox.SelectionLength;
                iLine = this.txtbox.GetLineIndexFromCharacterIndex(iChar);
                iCol = iChar - this.txtbox.GetCharacterIndexFromLineIndex(iLine);
                str += string.Format(" - Line {0} Col {1}", iLine + 1, iCol + 1);
            }

            this.statLineCol.Content = str;
        }

        private void TextBoxOnTextChanged(object sender, TextChangedEventArgs e)
        {
            this.isFileDirty = true;
        }
        #endregion
    }
}
